#pragma once

#include "StructuredActivityNode.h"

#include "Action.h"
#include "Activity.h"
#include "ActivityEdge.h"
#include "ActivityNode.h"
#include "InputPin.h"
#include "OutputPin.h"
#include "Variable.h"

namespace uml {

const bool StructuredActivityNode::mustIsolate_default_ = false;
StructuredActivityNode::StructuredActivityNode(const QString& umlType)
    : Action(umlType) {}

void StructuredActivityNode::fromJson(const QJsonObject& json, QStringList& errorList) {
    if (json.isEmpty()) {
        return;
    }

    Namespace::fromJson(json, errorList);
    Action::fromJson(json, errorList);
    ActivityGroup::fromJson(json, errorList);
    activity_ = JsonSerializable::create<Activity>(json.value("activity"), errorList);

    JsonSerializable::fromJsonArray(edges_, "edges", json, errorList);
    mustIsolate_ = json.value("mustIsolate").toBool(mustIsolate_default_);
    JsonSerializable::fromJsonArray(nodes_, "nodes", json, errorList);
    JsonSerializable::fromJsonArray(structuredNodeInputs_, "structuredNodeInputs", json, errorList);
    JsonSerializable::fromJsonArray(structuredNodeOutputs_, "structuredNodeOutputs", json, errorList);
    JsonSerializable::fromJsonArray(variables_, "variables", json, errorList);
}

void StructuredActivityNode::toJson(QJsonObject& json) {
    Namespace::toJson(json);
    Action::toJson(json);
    ActivityGroup::toJson(json);
    if (activity_) {
        QJsonObject activity_json;
        activity_->toJson(activity_json);
        json.insert("activity", activity_json);
    }
    JsonSerializable::toJsonArray(edges_, "edges", json);
    if (mustIsolate_ != mustIsolate_default_) {
        json.insert("mustIsolate", mustIsolate_);
    }
    JsonSerializable::toJsonArray(nodes_, "nodes", json);
    JsonSerializable::toJsonArray(structuredNodeInputs_, "structuredNodeInputs", json);
    JsonSerializable::toJsonArray(structuredNodeOutputs_, "structuredNodeOutputs", json);
    JsonSerializable::toJsonArray(variables_, "variables", json);
}

/// <summary>
/// allActions
    /// Returns this StructuredActivityNode and all Actions contained in it.
/// </summary>
    /// <code>
    /// result = (node->select(oclIsKindOf(Action)).oclAsType(Action).allActions()->including(self)->asSet())
    /// </code>
shared_ptr<vector<Action>> StructuredActivityNode::allActions() const
{
    return nullptr;
}

/// <summary>
/// allOwnedNodes
    /// Returns all the ActivityNodes contained directly or indirectly within this
    /// StructuredActivityNode, in addition to the Pins of the StructuredActivityNode.
/// </summary>
    /// <code>
    /// result = (self.Action::allOwnedNodes()->union(node)->union(node->select(oclIsKindOf(Action)).oclAsType(Action).allOwnedNodes())->asSet())
    /// </code>
shared_ptr<vector<ActivityNode>> StructuredActivityNode::allOwnedNodes() const
{
    return nullptr;
}

/// <summary>
/// sourceNodes
    /// Return those ActivityNodes contained immediately within the
    /// StructuredActivityNode that may act as sources of edges owned by the
    /// StructuredActivityNode.
/// </summary>
    /// <code>
    /// result = (node->union(input.oclAsType(ActivityNode)->asSet())->
    ///   union(node->select(oclIsKindOf(Action)).oclAsType(Action).output)->asSet())
    /// </code>
shared_ptr<vector<ActivityNode>> StructuredActivityNode::sourceNodes() const
{
    return nullptr;
}

/// <summary>
/// targetNodes
    /// Return those ActivityNodes contained immediately within the
    /// StructuredActivityNode that may act as targets of edges owned by the
    /// StructuredActivityNode.
/// </summary>
    /// <code>
    /// result = (node->union(output.oclAsType(ActivityNode)->asSet())->
    ///   union(node->select(oclIsKindOf(Action)).oclAsType(Action).input)->asSet())
    /// </code>
shared_ptr<vector<ActivityNode>> StructuredActivityNode::targetNodes() const
{
    return nullptr;
}

/// <summary>
/// containingActivity
    /// The Activity that directly or indirectly contains this StructuredActivityNode
    /// (considered as an Action).
/// </summary>
    /// <code>
    /// result = (self.Action::containingActivity())
    /// </code>
shared_ptr<Activity> StructuredActivityNode::containingActivity() const
{
    return nullptr;
}

/// <summary>
/// activity getter
/// The Activity immediately containing the StructuredActivityNode, if it is not
/// contained in another StructuredActivityNode.
/// </summary>
shared_ptr<Activity> StructuredActivityNode::activity() const {
    return activity_;
}

/// <summary>
/// activity setter
/// The Activity immediately containing the StructuredActivityNode, if it is not
/// contained in another StructuredActivityNode.
/// </summary>
void StructuredActivityNode::setActivity(shared_ptr<Activity> value) {
    activity_ = value;
}

/// <summary>
/// edges getter
/// The ActivityEdges immediately contained in the StructuredActivityNode.
/// </summary>
vector<shared_ptr<ActivityEdge>>& StructuredActivityNode::edges() {
    return edges_;
}

/// <summary>
/// mustIsolate getter
/// If true, then any object used by an Action within the StructuredActivityNode
/// cannot be accessed by any Action outside the node until the
/// StructuredActivityNode as a whole completes. Any concurrent Actions that would
/// result in accessing such objects are required to have their execution deferred
/// until the completion of the StructuredActivityNode.
/// 
/// </summary>
bool StructuredActivityNode::mustIsolate() const {
    return mustIsolate_;
}

/// <summary>
/// mustIsolate setter
/// If true, then any object used by an Action within the StructuredActivityNode
/// cannot be accessed by any Action outside the node until the
/// StructuredActivityNode as a whole completes. Any concurrent Actions that would
/// result in accessing such objects are required to have their execution deferred
/// until the completion of the StructuredActivityNode.
/// 
/// </summary>
void StructuredActivityNode::setMustIsolate(bool value) {
    mustIsolate_ = value;
}

/// <summary>
/// nodes getter
/// The ActivityNodes immediately contained in the StructuredActivityNode.
/// </summary>
vector<shared_ptr<ActivityNode>>& StructuredActivityNode::nodes() {
    return nodes_;
}

/// <summary>
/// structuredNodeInputs getter
/// The InputPins owned by the StructuredActivityNode.
/// </summary>
vector<shared_ptr<InputPin>>& StructuredActivityNode::structuredNodeInputs() {
    return structuredNodeInputs_;
}

/// <summary>
/// structuredNodeOutputs getter
/// The OutputPins owned by the StructuredActivityNode.
/// </summary>
vector<shared_ptr<OutputPin>>& StructuredActivityNode::structuredNodeOutputs() {
    return structuredNodeOutputs_;
}

/// <summary>
/// variables getter
/// The Variables defined in the scope of the StructuredActivityNode.
/// </summary>
vector<shared_ptr<Variable>>& StructuredActivityNode::variables() {
    return variables_;
}

} // namespace uml
